/// @file 运行管理器，使用task来实现运行，主要是处理需要while(true)的功能，同时支持停止的功能
#ifndef __UTOOLS_COLLAB_RUNUNTIL_TASK_H__
#define __UTOOLS_COLLAB_RUNUNTIL_TASK_H__

#include "../utools_cfg.h"

#include "collab_task.h"
#include "utcondition_variable.h"
#include "utmutex.h"

namespace utools::collab
{
    /// @brief 运行管理器，使用task来实现运行，主要是处理需要while(true)的功能，同时支持停止的功能
    /// @tparam CONTEXTION_FREE 是否是无上下文的任务，默认为false，即有上下文的任务
    template <bool CONTEXTION_FREE = false>
    class RunUntilTask
    {
    public:
        RunUntilTask() = default;
        /// @brief 构造函数：接受任意可调用对象
        template <typename Func, typename... Args,
                  typename = std::enable_if<!std::is_member_function_pointer<Func>::value>>
        RunUntilTask(Func &&func, Args &&...args)
        {
            this->bind(std::forward<Func>(func), std::forward<Args>(args)...);
        }

        /// @brief 构造函数：接受类成员函数
        template <typename ReturnType, typename T, typename... Args>
        RunUntilTask(ReturnType (T::*func)(Args...), T *obj, Args &&...args)
        {
            this->bind(func, obj, std::forward<Args>(args)...);
        }

        /// @brief 构造函数：接受静态函数或自由函数
        template <typename ReturnType, typename... Args>
        RunUntilTask(ReturnType (*func)(Args...), Args &&...args)
        {
            this->bind(func, std::forward<Args>(args)...);
        }

        /// @brief 右值引用构造函数
        /// @note 处理已经绑定好的函数
        RunUntilTask(std::function<void()> &&func)
        {
            __task.bind(std::move(func));
        }

        /// @brief 左值引用构造函数
        /// @note 处理已经绑定好的函数
        RunUntilTask(const std::function<void()> &func)
        {
            __task.bind(func);
        }

        virtual ~RunUntilTask() = default;

        /// @brief 设置运行任务
        /// @param func 可调用对象
        /// @param args 可变参数
        /// @return 返回任务对象本身
        template <typename Func, typename... Args,
                  typename = std::enable_if<!std::is_member_function_pointer<Func>::value>>
        Task &bind(Func &&func, Args &&...args)
        {
            __task.bind(std::forward<Func>(func), std::forward<Args>(args)...);
            return *this;
        }

        /// @brief 设置运行任务
        /// @param func 类成员函数
        /// @param obj 类对象指针
        /// @param args 可变参数
        /// @return 返回任务对象本身
        template <typename ReturnType, typename T, typename... Args>
        Task &bind(ReturnType (T::*func)(Args...), T *obj, Args &&...args)
        {
            __task.bind(func, obj, std::forward<Args>(args)...);
            return *this;
        }

        /// @brief 设置运行任务
        /// @param func 静态函数或自由函数
        /// @param args 可变参数
        /// @return 返回任务对象本身
        template <typename ReturnType, typename... Args>
        Task &bind(ReturnType (*func)(Args...), Args &&...args)
        {
            __task.bind(func, std::forward<Args>(args)...);
            return *this;
        }

        /// @brief 设置运行任务
        /// @note 处理已经绑定好的函数
        Task &bind(std::function<void()> &&func) noexcept
        {
            __task.bind(std::move(func));
            return *this;
        }

        /// @brief 设置运行任务
        /// @note 处理已经绑定好的函数
        Task &bind(const std::function<void()> &func) noexcept
        {
            __task.bind(func);
            return *this;
        }

        void stop()
        {
            if constexpr (!CONTEXTION_FREE)
            {
                ::utools::collab::UniqueLock lock(__mutex);
            }
            __running = false;
        }

    private:
        ::utools::collab::Mutex __mutex;
        bool __running{false};

        ::utools::collab::Task __task;

        /// @brief 运行任务
        /// @param task 任务
        void __run_until()
        {
            if constexpr (!CONTEXTION_FREE)
            {
                ::utools::collab::UniqueLock lock(__mutex);
                __running = true;
            }
            while (__running)
            {
                if constexpr (!CONTEXTION_FREE)
                {
                    lock.lock();
                }
                // TODO:增加包裹函数
                if constexpr (!CONTEXTION_FREE)
                {
                    lock.unlock();
                }
            }
        }
    };
}

#endif // __UTOOLS_COLLAB_RUNUNTIL_TASK_H__